package com.cml.common.config;

import com.cml.common.constant.NodeRole;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;

import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Configuration {
    private Logger logger = Logger.getLogger(Configuration.class);



    private static String RC_SERVER_ID = "rc.server.id";

    private static String RC_SERVER_PORT = "rc.server.port";

    private static String RC_SERVER_FOLLOWER_LIST = "rc.server.follower_list";

    private static String RC_SERVER_NODE_ROLE = "rc.server.node_role";

    private static String RC_SERVER_IP="rc.server.ip";

    private static String RC_SERVER_CLUSTER_NODE_COUNT = "rc.server.cluster.node.count";

    private static String RC_SERVER_DATA_DIR = "rc.server.data.dir";

    private static String RC_SERVICE_MANAGER_PORT="rc.service.manager.port";

    private static String SERVICE_HEARTBEAT_INTERVAL_TIME="service.heartbeat.interval.time";

    private String configFileName="rc.properties";

    private Integer nodeServerId;

    private Integer nodeServerPort;



    private String nodeFollowerServerList;

    private String nodeRole;



    private Integer clusterNodeCount=0;

    private String nodeIp;



    private String dataDir;



    private Integer serviceManagerPort;

    private int serviceHeartbeatIntervalTime=3000;

    private Configuration(){

    }
    public String getDataDir() {
        if(dataDir == null){
            dataDir=Configuration.class.getClassLoader().getResource("").getPath()+"/data";
        }
        return dataDir;
    }

    public int getServiceHeartbeatIntervalTime() {
        return serviceHeartbeatIntervalTime;
    }

    public Integer getServiceManagerPort() {
        return serviceManagerPort;
    }

    public void setServiceManagerPort(Integer serviceManagerPort) {
        this.serviceManagerPort = serviceManagerPort;
    }

    private String getConfigFileName() {
        return configFileName;
    }

    public Integer getNodeServerId() {
        return nodeServerId;
    }

    public Integer getNodeServerPort() {
        return nodeServerPort;
    }
    public Integer getClusterNodeCount() {
        return clusterNodeCount;
    }
    /**
     * 这里为啥不用map，因为ip有可能重复
     * @return
     */
    public List getNodeFollowerServerList() {
        List<Map> nodeFollowerServerListData = new ArrayList<Map>();
        if(StringUtils.isNotEmpty(nodeFollowerServerList)) {

            String[] nodeServerListSplit = this.nodeFollowerServerList.split(",");
            for (int i = 0; i < nodeServerListSplit.length; i++) {
                String[] nodeServerSplit = nodeServerListSplit[i].split(":");
                Map nodeFollowerServerMap = new HashMap();
                nodeFollowerServerMap.put("ip", nodeServerSplit[0]);
                nodeFollowerServerMap.put("port", nodeServerSplit[1]);
                nodeFollowerServerListData.add(nodeFollowerServerMap);
            }
        }
        return nodeFollowerServerListData;
    }

    public List getNodeOtherFollowerServerList(){
        List<Map> nodeFollowerServerList=getNodeFollowerServerList();
        Map curNodeServer = null;
        for(Map map :nodeFollowerServerList){
            if(this.getNodeIp().equals(map.get("ip")) && this.getNodeServerPort().equals(map.get("port"))){
                curNodeServer=map;
            }
        }
        if(curNodeServer!= null){
            nodeFollowerServerList.remove(curNodeServer);
        }
        return nodeFollowerServerList;
    }

    //获取配置排在当前节点之前的节点
    public List getBeforeFollowerServerList(){
        List<Map> nodeFollowerServerList=getNodeFollowerServerList();
        List<Map> beforeNodeFollowerServerList=getNodeFollowerServerList();
        for(Map map :nodeFollowerServerList){
            if(this.getNodeIp().equals(map.get("ip")) && this.getNodeServerPort().equals(map.get("port"))){
                break;
            }else{
                beforeNodeFollowerServerList.add(map);

            }
        }
        return beforeNodeFollowerServerList;
    }


    public String getNodeRole() {
        return nodeRole;
    }
    public String getNodeIp() {
        return nodeIp;
    }

    public void parse(String configFileName) throws IOException {
        if(StringUtils.isNotEmpty(configFileName)){
            this.configFileName = configFileName;
        }
        logger.info("当前使用配置文件为："+this.configFileName);
        InputStream fileInputStream =null;
        try {
            fileInputStream =  Configuration.class.getClassLoader().getResourceAsStream(this.configFileName);
            Properties properties = new Properties();
            properties.load(fileInputStream);
            this.nodeServerId= new Integer(properties.get(Configuration.RC_SERVER_ID).toString()) ;
            logger.info("配置参数"+Configuration.RC_SERVER_ID + ":"+nodeServerId);

            this.nodeServerPort= new Integer(properties.get(Configuration.RC_SERVER_PORT).toString()) ;
            logger.info("配置参数"+Configuration.RC_SERVER_PORT + ":"+nodeServerPort);

            this.nodeFollowerServerList= (String) properties.get(Configuration.RC_SERVER_FOLLOWER_LIST);
            logger.info("配置参数"+Configuration.RC_SERVER_FOLLOWER_LIST + ":"+nodeFollowerServerList);

            this.nodeRole= (String) properties.get(Configuration.RC_SERVER_NODE_ROLE);
            logger.info("配置参数"+Configuration.RC_SERVER_NODE_ROLE + ":"+nodeRole);

            this.clusterNodeCount=new Integer(properties.get(Configuration.RC_SERVER_CLUSTER_NODE_COUNT).toString()) ;
            logger.info("配置参数"+Configuration.RC_SERVER_CLUSTER_NODE_COUNT + ":"+clusterNodeCount);

            this.nodeIp=(String) properties.get(Configuration.RC_SERVER_IP);
            logger.info("配置参数"+Configuration.RC_SERVER_IP + ":"+nodeIp);

            this.dataDir=(String) properties.get(Configuration.RC_SERVER_DATA_DIR);
            logger.info("配置参数"+Configuration.RC_SERVER_DATA_DIR + ":"+dataDir);

            this.serviceManagerPort=new Integer( properties.get(Configuration.RC_SERVICE_MANAGER_PORT).toString());
            logger.info("配置参数"+Configuration.RC_SERVICE_MANAGER_PORT + ":"+serviceManagerPort);

            this.serviceHeartbeatIntervalTime= Integer.decode((String) properties.get(Configuration.SERVICE_HEARTBEAT_INTERVAL_TIME));
            logger.info("配置参数"+Configuration.SERVICE_HEARTBEAT_INTERVAL_TIME + ":"+serviceHeartbeatIntervalTime);


            validateConfigArg(this.validateNodeServerId(),Configuration.RC_SERVER_ID);
            validateConfigArg(this.validateNodeServerPort(),Configuration.RC_SERVER_PORT);
            validateConfigArg(this.validateNodeServerList(),Configuration.RC_SERVER_FOLLOWER_LIST);
            validateConfigArg(this.validateNodeServerIp(),Configuration.RC_SERVER_IP);

        } catch (IOException e) {
            throw new ConfigurationException(e.getMessage());
        } finally {
            if (fileInputStream != null){
                fileInputStream.close();;
            }
        }
    }

    private void validateConfigArg(boolean status,String arg){
        if(!status){
            logger.error(arg+"配置错误");
            throw new ConfigurationException(arg+"配置错误");
        }
    }

    private boolean validateNodeRole(){
        if(StringUtils.isNotEmpty(nodeRole)){
            return true;
        }else{
            return false;
        }

    }

    private boolean validateNodeServerList(){
        boolean verifyStatus= false;
        List<Map> nodeFollowerServerListData = getNodeFollowerServerList();
        if(nodeFollowerServerListData.size() > 0){
            for(Map nodeFollowerServer : nodeFollowerServerListData){
                String regex="^(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|[1-9])"
                        +"(\\.(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)){3}$";
                Pattern pattern = Pattern.compile(regex);
                Matcher matcher = pattern.matcher((String) nodeFollowerServer.get("ip"));
                boolean isMatched = matcher.matches();
                if(isMatched){
                    try {
                        Integer.parseInt((String) nodeFollowerServer.get("port"));
                        verifyStatus=true;
                    } catch (NumberFormatException e) {
                        logger.error(e);
                    }
                }
            }
        }
        return verifyStatus;
    }

    private boolean validateNodeServerIp(){
        if(StringUtils.isNotEmpty(nodeIp)){
            String regex="^(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|[1-9])"
                    +"(\\.(1\\d{2}|2[0-4]\\d|25[0-5]|[1-9]\\d|\\d)){3}$";
            Pattern pattern = Pattern.compile(regex);
            Matcher matcher = pattern.matcher(nodeIp);
           return matcher.matches();
        }
        return false;
    }

    private boolean validateNodeServerPort(){
        if(nodeServerPort > 0){
            return true;
        }else{
            return false;
        }

    }

    private boolean validateNodeServerId(){
        if(nodeServerId > 0){
            return true;
        }else{
            return false;
        }

    }

    private static class Singleton{
        private static Configuration INSTANCE = new Configuration();
    }

    public static Configuration getInstance(){
        return Singleton.INSTANCE;
    }

    public boolean isFollower(){
        return NodeRole.FOLLOWER.equals(this.getNodeRole());
    }
}
